#include "TestDocumentStreamWriter.h"

#include "DocumentObjectFactoryMock.h"
#include "DocumentObjectMock.h"

#include "LeDocumentObject/Document.h"
#include "LeDocumentObject/DocumentStreamWriter.h"

#include <QBuffer>
#include <QDebug>
#include <QTest>

void TestDocumentStreamWriter::testWriteSimpleObject()
{
    DocumentObjectMock1 mock;
    mock.setObjectName("ObjectName");
    mock.setObjectUserName("ObjectUserName");
    mock.setReal(3.1415);
    mock.setString("foo bar baz");
    mock.setInteger(42);
    mock.setEnumeration(DocumentObjectMock1::MockEnum1);
    mock.setFlags(DocumentObjectMock1::MockFlag1|DocumentObjectMock1::MockFlag3);
    LDO::DocumentStreamWriter writer;
    writer.setAutoFormatting(false);
    QBuffer buffer;
    buffer.open(QBuffer::WriteOnly);
    writer.setDevice(&buffer);

    writer.writeDocumentObject(&mock);

    QCOMPARE(QString(buffer.data()),
             QString("<property xmlns=\"https://libre-eda.org/xml-document/1.0\" name=\"string\" type=\"QString\">foo bar baz</property>"
                     "<property name=\"real\" type=\"double\">3.1415</property>"
                     "<property name=\"integer\" type=\"int\">42</property>"
                     "<property name=\"enumeration\" type=\"DocumentObjectMock1::MockEnum\">MockEnum1</property>"
                     "<property name=\"flags\" type=\"DocumentObjectMock1::MockFlags\">MockFlag1|MockFlag3</property>"
                     "<property name=\"stringList\" type=\"QStringList\"/>"));
}

void TestDocumentStreamWriter::testWriteSimpleDocument()
{
    LDO::Document doc;
    DocumentObjectFactoryMock factory;
    doc.registerFactory(&factory);
    DocumentObjectMock1 *mock = doc.addObject<DocumentObjectMock1>();
    mock->setObjectName("ObjectName");
    mock->setObjectUserName("ObjectUserName");
    mock->setReal(3.1415);
    mock->setString("foo bar baz");
    mock->setInteger(42);
    mock->setEnumeration(DocumentObjectMock1::MockEnum1);
    mock->setFlags(DocumentObjectMock1::MockFlag1|DocumentObjectMock1::MockFlag3);
    LDO::DocumentStreamWriter writer;
    writer.setAutoFormatting(false);
    QBuffer buffer;
    buffer.open(QBuffer::WriteOnly);
    writer.setDevice(&buffer);

    writer.writeDocument(&doc);

    dumpXml(buffer.data());

    QCOMPARE(QString(buffer.data()),
             QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
                     "<document xmlns=\"https://libre-eda.org/xml-document/1.0\">"
                     "<object class=\"DocumentObjectMock1*\">"
                     "<property name=\"string\" type=\"QString\">foo bar baz</property>"
                     "<property name=\"real\" type=\"double\">3.1415</property>"
                     "<property name=\"integer\" type=\"int\">42</property>"
                     "<property name=\"enumeration\" type=\"DocumentObjectMock1::MockEnum\">MockEnum1</property>"
                     "<property name=\"flags\" type=\"DocumentObjectMock1::MockFlags\">MockFlag1|MockFlag3</property>"
                     "<property name=\"stringList\" type=\"QStringList\"/>"
                     "</object>"
                     "</document>\n"));
}

void TestDocumentStreamWriter::testWriteNullObject()
{
    LDO::DocumentStreamWriter writer;
    writer.setAutoFormatting(false);
    QBuffer buffer;
    buffer.open(QBuffer::WriteOnly);
    writer.setDevice(&buffer);

    writer.writeDocumentObject(nullptr);

    dumpXml(buffer.data());

    QCOMPARE(QString(buffer.data()),
             QString(""));
}


void TestDocumentStreamWriter::testWriteNullSubObjectProperty()
{
    LDO::Document doc;
    DocumentObjectFactoryMock factory;
    doc.registerFactory(&factory);
    DocumentObjectMock2 *mock = doc.addObject<DocumentObjectMock2>();
    mock->setObjectName("ObjectName");
    mock->setObjectUserName("ObjectUserName");
    mock->setObject(nullptr);

    LDO::DocumentStreamWriter writer;
    writer.setAutoFormatting(false);
    QBuffer buffer;
    buffer.open(QBuffer::WriteOnly);
    writer.setDevice(&buffer);

    writer.writeDocument(&doc);

    dumpXml(buffer.data());

    QCOMPARE(QString(buffer.data()),
             QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
                     "<document xmlns=\"https://libre-eda.org/xml-document/1.0\">"
                     "<object class=\"DocumentObjectMock2*\"/>"
                     //"<property name=\"object\"/>"
                     //"</object>"
                     "</document>\n"));

}

void TestDocumentStreamWriter::testWriteSubObjectProperty()
{
    LDO::Document doc;
    DocumentObjectFactoryMock factory;
    doc.registerFactory(&factory);
    DocumentObjectMock2 *mock = doc.addObject<DocumentObjectMock2>();
    mock->setObjectName("ObjectName");
    mock->setObjectUserName("ObjectUserName");
    DocumentObjectMock1 *subMock = new DocumentObjectMock1();
    subMock->setObjectName("SubObjectName");
    subMock->setObjectUserName("SubObjectUserName");
    mock->setObject(subMock);

    LDO::DocumentStreamWriter writer;
    writer.setAutoFormatting(false);
    QBuffer buffer;
    buffer.open(QBuffer::WriteOnly);
    writer.setDevice(&buffer);

    writer.writeDocument(&doc);

    dumpXml(buffer.data());

    QCOMPARE(QString(buffer.data()),
             QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
                     "<document xmlns=\"https://libre-eda.org/xml-document/1.0\">"
                     "<object class=\"DocumentObjectMock2*\">"
                     "<property name=\"object\" type=\"DocumentObjectMock1*\">"
                      "<property name=\"string\" type=\"QString\"></property>"
                      "<property name=\"real\" type=\"double\">0</property>"
                      "<property name=\"integer\" type=\"int\">0</property>"
                      "<property name=\"enumeration\" type=\"DocumentObjectMock1::MockEnum\">MockEnum3</property>"
                      "<property name=\"flags\" type=\"DocumentObjectMock1::MockFlags\"></property>"
                      "<property name=\"stringList\" type=\"QStringList\"/>"
                     "</property>"
                     "</object>"
                     "</document>\n"));
}

void TestDocumentStreamWriter::testWriteSubObjectListProperty()
{
    LDO::Document doc;
    DocumentObjectFactoryMock factory;
    doc.registerFactory(&factory);
    DocumentObjectMock3 *mock = doc.addObject<DocumentObjectMock3>();
    mock->setObjectName("ObjectName");
    mock->setObjectUserName("ObjectUserName");
    QList<DocumentObjectMock1 *> objects;
    for (int i=0; i<3; i++)
    {
        DocumentObjectMock1 *subMock = new DocumentObjectMock1();
        subMock->setObjectName(QString("SubObjectName%1").arg(i));
        subMock->setObjectUserName(QString("SubObjectUserName%1").arg(i));
        objects.append(subMock);
    }
    mock->setObjects(objects);

    LDO::DocumentStreamWriter writer;
    writer.setAutoFormatting(false);
    QBuffer buffer;
    buffer.open(QBuffer::WriteOnly);
    writer.setDevice(&buffer);

    writer.writeDocument(&doc);

    dumpXml(buffer.data());

    QCOMPARE(QString(buffer.data()),
             QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
                     "<document xmlns=\"https://libre-eda.org/xml-document/1.0\">"
                     "<object class=\"DocumentObjectMock3*\">"
                     "<property name=\"objects\" type=\"QList&lt;DocumentObjectMock1*&gt;\">"
                     "<item>"
                     "<property name=\"string\" type=\"QString\"></property>"
                     "<property name=\"real\" type=\"double\">0</property>"
                     "<property name=\"integer\" type=\"int\">0</property>"
                     "<property name=\"enumeration\" type=\"DocumentObjectMock1::MockEnum\">MockEnum3</property>"
                     "<property name=\"flags\" type=\"DocumentObjectMock1::MockFlags\"></property>"
                     "<property name=\"stringList\" type=\"QStringList\"/>"
                     "</item>"
                     ""
                     "<item>"
                     "<property name=\"string\" type=\"QString\"></property>"
                     "<property name=\"real\" type=\"double\">0</property>"
                     "<property name=\"integer\" type=\"int\">0</property>"
                     "<property name=\"enumeration\" type=\"DocumentObjectMock1::MockEnum\">MockEnum3</property>"
                     "<property name=\"flags\" type=\"DocumentObjectMock1::MockFlags\"></property>"
                     "<property name=\"stringList\" type=\"QStringList\"/>"
                     "</item>"
                     ""
                     "<item>"
                     "<property name=\"string\" type=\"QString\"></property>"
                     "<property name=\"real\" type=\"double\">0</property>"
                     "<property name=\"integer\" type=\"int\">0</property>"
                     "<property name=\"enumeration\" type=\"DocumentObjectMock1::MockEnum\">MockEnum3</property>"
                     "<property name=\"flags\" type=\"DocumentObjectMock1::MockFlags\"></property>"
                     "<property name=\"stringList\" type=\"QStringList\"/>"
                     "</item>"
                     ""
                     "</property>"
                     "</object>"
                     "</document>\n"));

}

void TestDocumentStreamWriter::dumpXml(const QByteArray &data)
{
    if (!m_debug)
        return;

    for (auto str: QString(data).split("<"))
        qDebug() << QString("<%1").arg(str);
}
